/*
Run process as child
*/

#include <stdio.h>	/* header for fprintf() */
#include <strings.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>	/* header for fork() */
#include <time.h>



char *strconc(char *s1, char *s2)
{
	char *s3 = s1, *result;
	result = malloc(strlen(s3) + strlen(s2) + 1);
	if (result)
	{
		strcpy(result, s3);
		strcat(result, s2);
	}
	return result;
}


int main(int argc, char *argv[])
   {
   /* must be called with an argument */
	if (argc < 3)
	{
		fprintf(stderr,"Usage: %s {twm folder} {comands}\n", argv[0]);
		exit(1);
	}

	int is_debug = 1;
	char *twmfolder = argv[1]; // get TrafficPanel folder "/usr/local/twm"
	char *forker_err_log = strconc(twmfolder, "/logs/forker.err.log");
	char *forker_out_log = strconc(twmfolder, "/logs/forker.out.log");

	char *env[] = {
		"PATH=/bin:/usr/bin:/usr/sbin/",
		strconc("TWMFOLDER=", twmfolder),//"TWMFOLDER=/usr/local/twm/"
		NULL};

	int param_length = argc-1;
	char *param[param_length];
	int i;

	for (i=0; i<param_length-1; i++)
		param[i] = argv[i+2];
	param[param_length-1] = NULL;
//	for (i=0; i<param_length-1; i++) printf("\n Param %d with value %s \n", i, param[i]);


	setuid(0);  /* become root */


	if (is_debug > 1)
		printf("Duplicate std_err \n"); 
// duplicate std_err
	int errfile;
	if ((errfile = dup(2))==-1) 
	{
		if (is_debug > 0)
			printf("Could not dup std_err \n"); 
		exit(1);
	}

	if (is_debug > 1)
		printf("Duplicate std_out \n"); 
// duplicate std_out
	int outfile;
	if ((outfile = dup(1))==-1) 
	{
		if (is_debug > 0)
			printf("Could not dup std_out \n"); 
		exit(1);
	}


	switch (fork())
	{
		case 0 :
 			if (is_debug > 1)
				printf("\n Created pid %d with ppid %d \n", getpid(), getppid());

			// becomes group leader
			if (setsid()<0)
			{
				if (is_debug > 0)
					printf("Could not set sid\n");
				exit(1);
			}
/*
// system V does not require second fork. may be bsd requires. 
			switch (fork())
			{
				case 0:  
					if (is_debug > 1)
						printf("\n Created pid %d with ppid %d \n", getpid(), getppid()); 
					break;
			        case -1: 
					if (is_debug > 1)
						printf("\n Error second fork \n"); 
					exit(1);
			        default: 
					if (is_debug > 1)
						printf(" Current pid is %d with ppid %d \n", getpid(), getppid()); 
					exit(0);
			}
*/



			int i;
			// close all descriptors
			if (is_debug > 1)
				printf("Close all parent descriptors \n"); 
			for (i=getdtablesize();i>=0;--i) 
			{
				if (is_debug > 2)
					printf("Close descriptor: %d \n", i); 
				close(i);
			}

			// need open new output table to file
			if (
				(
					is_debug > 0
					&&
					(errfile=open(forker_err_log, O_WRONLY|O_CREAT|O_APPEND,00640))>=0
					&&
					(outfile=open(forker_out_log, O_WRONLY|O_CREAT|O_APPEND,00640))>=0
				)
				||
				(
					(errfile=open("/dev/null", O_WRONLY))>=0 
					&&
					(outfile=open("/dev/null", O_WRONLY))>=0
				)
			)
			{
				if (is_debug > 0)
				{
					char date_str[200];
					time_t t;
					struct tm *tmp;
					t = time(NULL);
					tmp = localtime(&t);
					if (tmp == NULL)
					{
						perror("localtime");
						exit(EXIT_FAILURE);
					}
					if (strftime(date_str, sizeof(date_str), "%d %b %Y %H:%M:%S", tmp) == 0)
					{
						fprintf(stderr, "strftime returned 0");
						exit(EXIT_FAILURE);
					}
					printf("\n\n%s\n", date_str); 

					char *args = "";
					for (i=0; i<param_length-1; i++)
						args = strconc(strconc(args, " "), param[i]);
					printf("Exec: %s\n", args); 
				}
				execve(param[0], param, env);
//				close(outfile);
//				close(errfile);				
			}
			exit(0);
		case -1 :
			if (is_debug > 0)
				printf("\n Error first fork \n");
			exit(1);
		default :
			if (is_debug > 0)
				printf(" Current pid is %d with ppid %d \n", getpid(), getppid());
			exit(0);
	}
   }
